﻿/*
 *
 *
 * 一个OnPointerUpClick的源码分析(有空可研究为什么不触发）
 * https://www.cnblogs.com/msxh/p/10588783.html
 */
using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using kernal;//现在在 Standard Assets/EasyButton/
using UnityEngine.EventSystems;
using UnityEngine.UI;
// ReSharper disable DelegateSubtraction

public enum SkillAreaType
{
    OuterCircle = 0,
    OuterCircle_InnerCube = 1,
    OuterCircle_InnerSector = 2,
    OuterCircle_InnerCircle = 3,
}
/// <summary>
/// 预制体：Standard Assets/SkillIndicator/CanvasJoystick.prefab
/// </summary>
public class SkillArea : MonoBehaviour
{

    public bool dontHide4Test;
    /// <summary>
    /// X 取消技能按钮
    /// </summary>
    public Image m_ReturnButton;

    public Action onReturnFunction;
    private bool _isPointerEnterClose;
    //private Camera _cameraMain; //用了会省性能，但就没法切换场景直接用【指示器】，所以暂时不用这个变量
    enum SKillAreaElement
    {
        OuterCircle,    // 外圆
        InnerCircle,    // 内圆
        Cube,           // 矩形 
        Sector60,        // 扇形
        Sector120,        // 扇形
    }

    SkillJoystick _joystick;
    [Header("场景中需要:EventSystem")]
    [Header("需要手动或代码设置Player")]
    public GameObject player;      

    [Header("技能指示器可选")]
    public SkillAreaType areaType;      // 设置指示器类型

    Vector3 deltaVec;

    float outerRadius = 6;      // 外圆半径
    float innerRadius = 2f;     // 内圆半径
    float cubeWidth = 2f;       // 矩形宽度 （矩形长度使用的外圆半径）
    int angle = 60;             // 扇形角度

    bool isPressed = false;


    string path = "SkillIndicatorEffect/Prefabs/Hero_skillarea/";  // 路径
    string circle = "quan_hero";    // 圆形
    string cube = "chang_hero";     // 矩形
    string sector60 = "shan_hero_60";    // 扇形60度
    string sector120 = "shan_hero_120";    // 扇形120度

    Dictionary<SKillAreaElement, string> allElementPath;
    Dictionary<SKillAreaElement, Transform> allElementTrans;

    private Dictionary<SKillAreaElement, Color?> allEleDefColor;
    /// <summary>
    /// 指示器变色用（之后可能会是数组）
    /// </summary>
    private SKillAreaElement _currElementType;
    
    // Use this for initialization
    public Color ColorCurrDef
    {
        get
        {
            if (allElementTrans == null) return Color.white;
            var trans = allElementTrans[_currElementType];
            if (trans == null) return Color.white;
            var col = allEleDefColor[_currElementType];
            return col!=null ? col.Value : Color.white;
        }
    }
    [HideInInspector]
    public string m_StateTurn;

    void Start()
    {
        _joystick = GetComponent<SkillJoystick>();

        _joystick.onJoystickDownEvent += OnJoystickDownEvent;
        _joystick.onJoystickMoveEvent += OnJoystickMoveEvent;
        _joystick.onJoystickUpEvent += OnJoystickUpEvent;

        InitSkillAreaType();

        if (m_ReturnButton != null)
        {
            EventTriggerListener.Get(m_ReturnButton.gameObject).onExit += OnSkillCloseButtonExit;
            EventTriggerListener.Get(m_ReturnButton.gameObject).onEnterPoint += OnSkillCloseButtonEnterPointer;
            
            //不会多个Ui,触发，Joystick本身时一个ui，所以只会在Joystick触发一次up,需要在OnJoystickUpEvent（）处理这个事件
            //至于原理分析，请看这个类的参考链接
            //EventTriggerListener.Get(m_ReturnButton.gameObject).onUp += OnSkillCloseButtonUp;
        }
    }

    public bool IsShown()
    {
        Transform parent = GetParent();
        if (parent == null) return false;
        //parent == skillArea
        return parent.gameObject.activeSelf;
    }
    // void OnSkillCloseButtonUp(GameObject sender)
    // {
    //     测试过并不会触发
    //     Debug.LogError("indicator up");
    //     onReturnFunction?.Invoke();
    // }

    void OnSkillCloseButtonExit(GameObject sender)
    {
        _isPointerEnterClose = false;
        ChangeCurrColor(ColorCurrDef);
    }

    void OnSkillCloseButtonEnterPointer(GameObject sender, PointerEventData data)
    {
        _isPointerEnterClose = true;
        ChangeCurrColor(Color.red);
        
    }

    void OnDestroy()
    {
        _joystick.onJoystickDownEvent -= OnJoystickDownEvent;
        _joystick.onJoystickMoveEvent -= OnJoystickMoveEvent;
        _joystick.onJoystickUpEvent -= OnJoystickUpEvent;
    }

    void InitSkillAreaType()
    {
        allElementPath = new Dictionary<SKillAreaElement, string>();
        allElementPath.Add(SKillAreaElement.OuterCircle, circle);
        allElementPath.Add(SKillAreaElement.InnerCircle, circle);
        allElementPath.Add(SKillAreaElement.Cube, cube);
        allElementPath.Add(SKillAreaElement.Sector60, sector60);
        allElementPath.Add(SKillAreaElement.Sector120, sector120);

        allElementTrans = new Dictionary<SKillAreaElement, Transform>();
        allElementTrans.Add(SKillAreaElement.OuterCircle, null);
        allElementTrans.Add(SKillAreaElement.InnerCircle, null);
        allElementTrans.Add(SKillAreaElement.Cube, null);
        allElementTrans.Add(SKillAreaElement.Sector60, null);
        allElementTrans.Add(SKillAreaElement.Sector120, null);
        
        allEleDefColor = new Dictionary<SKillAreaElement, Color?>();
        allEleDefColor.Add(SKillAreaElement.OuterCircle, null);
        allEleDefColor.Add(SKillAreaElement.InnerCircle, null);
        allEleDefColor.Add(SKillAreaElement.Cube, null);
        allEleDefColor.Add(SKillAreaElement.Sector60, null);
        allEleDefColor.Add(SKillAreaElement.Sector120, null);
    }

    public Vector3 GetIndicatorLocate()
    {
        if (allElementTrans[SKillAreaElement.Sector60] == null) return Vector3.zero;

        var ele = allElementTrans[SKillAreaElement.Sector60];
        return player.transform.position + ele.transform.forward * 2;
    }

    void OnJoystickDownEvent(Vector2 deltaVec)
    {
        isPressed = true;
        this.deltaVec = new Vector3(deltaVec.x, 0, deltaVec.y);
        CreateSkillArea();
    }

    void OnJoystickUpEvent()
    {
        isPressed = false;
        if(!dontHide4Test)
            HideElements();
        
        if(_isPointerEnterClose==true)
        {
            //onReturnFunction?.Invoke();
            if(onReturnFunction!=null)
                onReturnFunction.Invoke();
        }

    }

    void OnJoystickMoveEvent(Vector2 deltaVec)
    {
        this.deltaVec = new Vector3(deltaVec.x, 0, deltaVec.y);
    }

    void LateUpdate()
    {
        if(isPressed)
            UpdateElement();
    }

    public void PreShowArea()
    {
        CreateSkillArea();
    }

    /// <summary>
    /// 创建技能区域展示
    /// </summary>
    void CreateSkillArea()
    {
        //每次显示，刷新状态（必须）
        _isPointerEnterClose = false;
        _currElementType = SKillAreaElement.OuterCircle; 
        switch (areaType)
        {
            case SkillAreaType.OuterCircle:
                CreateElement(SKillAreaElement.OuterCircle);
             //   elementType = SKillAreaElement.OuterCircle;
                break;
            case SkillAreaType.OuterCircle_InnerCube:
                CreateElement(SKillAreaElement.OuterCircle);
                CreateElement(SKillAreaElement.Cube);
               // elementType = SKillAreaElement.OuterCircle;
                break;
            case SkillAreaType.OuterCircle_InnerSector:
                CreateElement(SKillAreaElement.OuterCircle);
                switch (angle)
                {
                    case 60:
                        CreateElement(SKillAreaElement.Sector60);
                        break;
                    case 120:
                        CreateElement(SKillAreaElement.Sector120);
                        break;
                    default:
                        break;
                }
                break;
            case SkillAreaType.OuterCircle_InnerCircle:
                CreateElement(SKillAreaElement.OuterCircle);
                CreateElement(SKillAreaElement.InnerCircle);
                break;
            default:
                break;
        }
        
    }

    

    public void ChangeCurrColor(Color col)
    {
        var transCore = allElementTrans[_currElementType];
        var mat = transCore.GetComponentInChildren<Renderer>();
        if (mat)
        {
            //mat.sharedMaterial.SetColor(TintColor,col);
            mat.material.SetColor("_TintColor",col);
        }
    }

    /// <summary>
    /// 创建技能区域展示元素
    /// </summary>
    /// <param name="element"></param>
	void CreateElement(SKillAreaElement element)
    {
        Transform elementTrans = GetElement(element);
        if (elementTrans == null) return;
        allElementTrans[element] = elementTrans;
        if (allEleDefColor[element] == null)
        {
            var defaultMat = elementTrans.GetComponentInChildren<Renderer>();
            if (defaultMat != null)
            {
                if (defaultMat.sharedMaterial != null)
                {
                    Color defaultCol = defaultMat.sharedMaterial.GetColor("_TintColor");
                    allEleDefColor[element] = defaultCol;
                }
            }
        }

        switch (element)
        {
            case SKillAreaElement.OuterCircle:
                elementTrans.localScale = new Vector3(outerRadius * 2, 1, outerRadius * 2) / player.transform.localScale.x;
                elementTrans.gameObject.SetActive(true);
                break;
            case SKillAreaElement.InnerCircle:
                elementTrans.localScale = new Vector3(innerRadius * 2, 1, innerRadius * 2) / player.transform.localScale.x;
                break;
            case SKillAreaElement.Cube:
                elementTrans.localScale = new Vector3(cubeWidth, 1, outerRadius) / player.transform.localScale.x;
                break;
            case SKillAreaElement.Sector60:
            case SKillAreaElement.Sector120:
                elementTrans.localScale = new Vector3(outerRadius, 1, outerRadius) / player.transform.localScale.x;
                break;
            default:
                break;
        }
    }

    Transform elementParent;
    //private readonly int TintColor = Shader.PropertyToID("_TintColor");//这个方法貌似不能静态使用

    /// <summary>
    /// 获取元素的父对象
    /// </summary>
    /// <returns></returns>
    Transform GetParent()
    {
        if (player == null) return null;
        if (elementParent == null)
        {
            elementParent = player.transform.Find("SkillArea");
        }
        if (elementParent == null)
        {
            elementParent = new GameObject("SkillArea").transform;
            elementParent.parent = player.transform;
            elementParent.localEulerAngles = Vector3.zero;
            elementParent.localPosition = Vector3.zero;
            elementParent.localScale = Vector3.one;
        }

        elementParent.SetParent(player.transform,false);
        return elementParent;
    }
    /// <summary>
    /// 本来想在SetPlayer做额外处理，现在在每次 GetParent() 已处理 player 切换的情况，不需要了
    /// </summary>
    /// <param name="pp"></param>
    public void ResetPlayer(GameObject pp)
    {
        this.player = pp;
        // if(elementParent!=null)
        //     elementParent.parent = player.transform;
    }

    /// <summary>
    /// 获取元素物体
    /// </summary>
    Transform GetElement(SKillAreaElement element)
    {
        if (player == null) return null;
        string name = element.ToString();
        Transform parent = GetParent();
        Transform elementTrans = parent.Find(name);
        if (elementTrans == null)
        {
            GameObject elementGo = Instantiate(Resources.Load(path + allElementPath[element])) as GameObject;
            elementGo.transform.parent = parent;
            elementGo.gameObject.SetActive(false);
            elementGo.name = name;
            elementTrans = elementGo.transform;
        }
        elementTrans.localEulerAngles = Vector3.zero;
        elementTrans.localPosition = Vector3.zero;
        elementTrans.localScale = Vector3.one;
        return elementTrans;
    }

    /// <summary>
    /// 隐藏所有元素
    /// </summary>
    void HideElements()
    {
        if (player == null) return;
        Transform parent = GetParent();
        for (int i = 0, length = parent.childCount; i < length; i++)
        {
            parent.GetChild(i).gameObject.SetActive(false);
        }
    }

    /// <summary>
    /// 隐藏指定元素
    /// </summary>
    /// <param name="element"></param>
    void HideElement(SKillAreaElement element)
    {
        if (player == null) return;
        Transform parent = GetParent();
        Transform elementTrans = parent.Find(element.ToString());
        if (elementTrans != null)
            elementTrans.gameObject.SetActive(false);
    }

    /// <summary>
    /// 每帧更新元素
    /// </summary>
    void UpdateElement()
    {
        switch (areaType)
        {
            case SkillAreaType.OuterCircle:
                break;
            case SkillAreaType.OuterCircle_InnerCube:
                UpdateElementPosition(SKillAreaElement.Cube);
                break;
            case SkillAreaType.OuterCircle_InnerSector:
                switch (angle)
                {
                    case 60:
                        UpdateElementPosition(SKillAreaElement.Sector60);
                        break;
                    case 120:
                        UpdateElementPosition(SKillAreaElement.Sector120);
                        break;
                    default:
                        break;
                }
                break;
            case SkillAreaType.OuterCircle_InnerCircle:
                UpdateElementPosition(SKillAreaElement.InnerCircle);
                break;
            default:
                break;
        }
    }

    /// <summary>
    /// 每帧更新元素位置
    /// </summary>
    /// <param name="element"></param>
    void UpdateElementPosition(SKillAreaElement element)
    {
        if (allElementTrans[element] == null)
            return;
        switch (element)
        {
            case SKillAreaElement.OuterCircle:
                break;
            case SKillAreaElement.InnerCircle:
                allElementTrans[element].transform.position = GetCirclePosition(outerRadius);
                break;
            case SKillAreaElement.Cube:
            case SKillAreaElement.Sector60:
            case SKillAreaElement.Sector120:
                allElementTrans[element].transform.LookAt(GetCubeSectorLookAt());
                break;
            default:
                break;
        }
        if (!allElementTrans[element].gameObject.activeSelf)
            allElementTrans[element].gameObject.SetActive(true);
    }

    /// <summary>
    /// 获取InnerCircle元素位置
    /// </summary>
    /// <returns></returns>
    Vector3 GetCirclePosition(float dist)
    {
        if (player == null) return Vector3.zero;

        Vector3 targetDir = deltaVec * dist;

        float y = Camera.main.transform.rotation.eulerAngles.y;
        targetDir = Quaternion.Euler(0, y, 0) * targetDir;

        return targetDir + player.transform.position;
    }

    /// <summary>
    /// 获取Cube、Sector元素朝向
    /// </summary>
    /// <returns></returns>
    Vector3 GetCubeSectorLookAt()
    {
        if (player == null) return Vector3.zero;
        
        Vector3 targetDir = deltaVec;

        float y = Camera.main.transform.rotation.eulerAngles.y;
        targetDir = Quaternion.Euler(0, y, 0) * targetDir;

        return targetDir + player.transform.position;
    }

    
}
